package com.moon.cloud.common.utils;

import com.alibaba.fastjson2.JSON;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;

import java.beans.PropertyDescriptor;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * Bean 工具类
 */
public class BeanUtils {

    /**
     * Bean 属性拷贝（Spring BeanUtils）
     */
    public static void copyProperties(Object source, Object target) {
        if (source == null || target == null) {
            return;
        }
        org.springframework.beans.BeanUtils.copyProperties(source, target);
    }

    /**
     * Bean 属性拷贝（忽略 null 值）
     */
    public static void copyPropertiesIgnoreNull(Object source, Object target) {
        if (source == null || target == null) {
            return;
        }
        org.springframework.beans.BeanUtils.copyProperties(source, target, getNullPropertyNames(source));
    }

    /**
     * Bean 转换（创建新对象）
     */
    public static <T> T convert(Object source, Class<T> targetClass) {
        if (source == null) {
            return null;
        }
        try {
            T target = targetClass.getDeclaredConstructor().newInstance();
            copyProperties(source, target);
            return target;
        } catch (Exception e) {
            throw new RuntimeException("Bean conversion failed", e);
        }
    }

    /**
     * Bean 转换（忽略 null 值）
     */
    public static <T> T convertIgnoreNull(Object source, Class<T> targetClass) {
        if (source == null) {
            return null;
        }
        try {
            T target = targetClass.getDeclaredConstructor().newInstance();
            copyPropertiesIgnoreNull(source, target);
            return target;
        } catch (Exception e) {
            throw new RuntimeException("Bean conversion failed", e);
        }
    }

    /**
     * List Bean 转换
     */
    public static <S, T> List<T> convertList(Collection<S> sourceList, Class<T> targetClass) {
        if (CollectionUtils.isEmpty(sourceList)) {
            return new ArrayList<>();
        }
        return sourceList.stream()
                .map(source -> convert(source, targetClass))
                .collect(Collectors.toList());
    }

    /**
     * List Bean 转换（自定义转换函数）
     */
    public static <S, T> List<T> convertList(Collection<S> sourceList, Function<S, T> converter) {
        if (CollectionUtils.isEmpty(sourceList)) {
            return new ArrayList<>();
        }
        return sourceList.stream()
                .map(converter)
                .collect(Collectors.toList());
    }

    /**
     * List Bean 转换为 Map
     */
    public static <S, T, K> Map<K, T> convertToMap(Collection<S> sourceList, Class<T> targetClass, Function<T, K> keyMapper) {
        if (CollectionUtils.isEmpty(sourceList)) {
            return new HashMap<>();
        }
        return sourceList.stream()
                .map(source -> convert(source, targetClass))
                .collect(Collectors.toMap(keyMapper, Function.identity(), (v1, v2) -> v1));
    }

    /**
     * Bean 转 Map（使用 FastJson2）
     */
    @SuppressWarnings("unchecked")
    public static Map<String, Object> beanToMap(Object bean) {
        if (bean == null) {
            return null;
        }
        String json = JSON.toJSONString(bean);
        return JSON.parseObject(json, Map.class);
    }

    /**
     * Map 转 Bean（使用 FastJson2）
     */
    public static <T> T mapToBean(Map<String, Object> map, Class<T> beanClass) {
        if (map == null) {
            return null;
        }
        String json = JSON.toJSONString(map);
        return JSON.parseObject(json, beanClass);
    }

    /**
     * 获取对象中的 null 属性名称
     */
    private static String[] getNullPropertyNames(Object source) {
        final BeanWrapper src = new BeanWrapperImpl(source);
        PropertyDescriptor[] pds = src.getPropertyDescriptors();

        Set<String> emptyNames = new HashSet<>();
        for (PropertyDescriptor pd : pds) {
            Object srcValue = src.getPropertyValue(pd.getName());
            if (srcValue == null) {
                emptyNames.add(pd.getName());
            }
        }
        String[] result = new String[emptyNames.size()];
        return emptyNames.toArray(result);
    }

    /**
     * 判断 Bean 是否为空（所有属性都为 null）
     */
    public static boolean isEmpty(Object bean) {
        if (bean == null) {
            return true;
        }
        BeanWrapper beanWrapper = new BeanWrapperImpl(bean);
        PropertyDescriptor[] pds = beanWrapper.getPropertyDescriptors();
        for (PropertyDescriptor pd : pds) {
            if (!"class".equals(pd.getName())) {
                Object value = beanWrapper.getPropertyValue(pd.getName());
                if (value != null) {
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * 判断 Bean 是否不为空
     */
    public static boolean isNotEmpty(Object bean) {
        return !isEmpty(bean);
    }

    /**
     * 克隆对象（深拷贝，使用 FastJson2）
     */
    public static <T> T clone(T obj, Class<T> clazz) {
        if (obj == null) {
            return null;
        }
        String json = JSON.toJSONString(obj);
        return JSON.parseObject(json, clazz);
    }

    /**
     * List 深拷贝（使用 FastJson2）
     */
    public static <T> List<T> cloneList(List<T> list, Class<T> clazz) {
        if (list == null) {
            return null;
        }
        String json = JSON.toJSONString(list);
        return JSON.parseArray(json, clazz);
    }

    /**
     * 合并两个 Bean（source 覆盖 target）
     */
    public static <T> T merge(T target, T source) {
        if (source == null) {
            return target;
        }
        if (target == null) {
            return source;
        }
        copyPropertiesIgnoreNull(source, target);
        return target;
    }

    /**
     * 比较两个 Bean 是否相等（使用 FastJson2）
     */
    public static boolean equals(Object obj1, Object obj2) {
        if (obj1 == obj2) {
            return true;
        }
        if (obj1 == null || obj2 == null) {
            return false;
        }
        String json1 = JSON.toJSONString(obj1);
        String json2 = JSON.toJSONString(obj2);
        return Objects.equals(json1, json2);
    }
}
